﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;
using System.Threading;

namespace pshcli
{
    public class ExcelWriter
    {
        #region EXCEL_CELL_OFFSETS
        private const int baseidx = 13;
        private const string namecell = "C5";

        private const string m_serial = "C";
        private const string m_nt = "D";
        private const string m_tpl = "E";
        private const string m_mpinet = "F";

        private const string u_serial = "G";
        private const string u_nt = "H";
        private const string u_openmp = "I";
        private const string u_mpi = "J";

        private const string gs_sum_exec_name_col = "A";
        private const string gs_sum_exec_value_col = "B";
        private const int gs_exec_sum_row = 5;


        //Dwarf name	Platform	Parallel	Input	Timing	"Input file"	"Result file"	"Profile file"
        private const string gs_dwarf_exec_dname_col = "A";
        private const string gs_dwarf_exec_dplatform_col = "B";
        private const string gs_dwarf_exec_dparallel_col = "C";
        private const string gs_dwarf_exec_dsize_col = "D";
        private const string gs_dwarf_exec_dtiming_col = "E";
        private const string gs_dwarf_exec_dinfile_col = "F";
        private const string gs_dwarf_exec_drfile_col = "G";
        private const string gs_dwarf_exec_dpfile_col = "H";
        private const string gs_dwarf_exec_execstr_col = "I";

        private const int gs_dwarf_sum_row = 25;
        #endregion

        public static bool ExcelInstalled()
        {
            try
            {
                Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();

                xl.Quit();
                xl = null;
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        private static Worksheet FindSheet(string name, Sheets sheets)
        {
            System.Collections.IEnumerator worksheets = sheets.GetEnumerator();

            while (worksheets.MoveNext())
            {
                Worksheet wsCurrent = (Worksheet)worksheets.Current;
                if (name.Equals(wsCurrent.Name))
                    return wsCurrent;
            }

            throw new Exception("Dwarf-Plot: Could not find worksheet for dwarf: " + name);
        }

        public static void WriteResultsToExcelFile(string excelfilename, GlobalSettings gsettings, List<Dwarf2> dwarfs, bool createnewfile)
        {
            Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();
            xl.Visible = false;
            xl.DisplayAlerts = true; //false

            Microsoft.Office.Interop.Excel.Workbook workbook = null;

            if (createnewfile)
            {
                workbook = xl.Workbooks.Add(Type.Missing);
            }
            else
            {
                workbook = xl.Workbooks.Open(
                    excelfilename,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing,
                    Type.Missing);
            }


            try
            {
                Microsoft.Office.Interop.Excel.Sheets sheets = workbook.Worksheets;

                string timeflag = System.DateTime.Now.ToString().Replace("/", "_").Replace(":", "_");

                Worksheet sheet = (Worksheet)sheets.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                sheet.Name = "Summary " + timeflag;

                #region WRITE HEADER

                Range r = sheet.get_Range("A1", "K500");
                r.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignLeft;
                r.ColumnWidth = 20;

                ((Range)sheet.Columns["A", Type.Missing]).ColumnWidth = 36;
                ((Range)sheet.Columns["B", Type.Missing]).ColumnWidth = 25;

                r = sheet.get_Range("A1", "A1");
                r.Font.Bold = true;
                r.Cells.Value2 = "Parallel Dwarfs Project";

                r = sheet.get_Range("A2", "O2");
                r.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);

                r = sheet.get_Range("A2", "A2");
                r.Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.White);
                r.Font.Size = 36;
                r.Font.Bold = true;
                r.Cells.Value2 = "DwarfBench";



                r = sheet.get_Range("A4", "A4");
                r.Font.Bold = true;
                r.Cells.Value2 = "EXECUTION CONFIGURATION SUMMARY";
                r.Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.OrangeRed);

                r = sheet.get_Range("A24", "A24");
                r.Font.Bold = true;
                r.Cells.Value2 = "EXECUTION RESULTS SUMMARY";
                r.Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.OrangeRed);

                r = (Range)sheet.Rows["25", Type.Missing];
                r.Font.Bold = true;
                //r.Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.OrangeRed);

                r = sheet.get_Range("A25", "A25");
                r.Cells.Value2 = "Dwarf name";
                r = sheet.get_Range("B25", "B25");
                r.Cells.Value2 = "Platform";
                r = sheet.get_Range("C25", "C25");
                r.Cells.Value2 = "Parallel";
                r = sheet.get_Range("D25", "D25");
                r.Cells.Value2 = "Input";
                r = sheet.get_Range("E25", "E25");
                r.Cells.Value2 = "Timing";
                r = sheet.get_Range("F25", "F25");
                r.Cells.Value2 = "Input file";
                r = sheet.get_Range("G25", "G25");
                r.Cells.Value2 = "Result file";
                r = sheet.get_Range("H25", "H25");
                r.Cells.Value2 = "Profile file";
                r = sheet.get_Range("I25", "I25");
                r.Cells.Value2 = "Execution string";

                #endregion


                string name_col = gs_sum_exec_name_col;
                string value_col = gs_sum_exec_value_col;
                int row = gs_exec_sum_row;

                #region WRITE SUMMARY
                //DATE TIME
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Execution time";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = System.DateTime.Today.ToString();
                //XML CONFIG FILE
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Xml config file";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.xmlconfigfile;
                //THREAD COUNT
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Thread count";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.threadcount;
                //MPI PROC COUNT
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "MPI proc count";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.mpiproccount;
                //HPC SCHEDULER
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "HPC scheduler";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.hpcscheduler;
                //EXECUTION ON CLUSTER
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Execution on cluster enabled";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.runoncluster.ToString().ToLower();
                //RESOURCE ALLOCATION
                if (!String.IsNullOrEmpty(gsettings.cluster_resource_alloc_level))
                {
                    row++;
                    sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Execution on cluster enabled";
                    sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.runoncluster.ToString().ToLower();
                }

                //XPERF TRACING
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Xperf tracing enabled";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.xperftracingenabled.ToString().ToLower();
                //XPERF COUNTER SELECT
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Xperf tracing counter selection";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.xperfcounterselect;
                //MPI TRACING
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Mpi tracing enabled";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.mpitracingenabled.ToString().ToLower();
                //MPI COUNTER SELECT
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Mpi exec string";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.mpicounterselect;
                //DWARF DIRECTORY
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = "";
                //DWARF DIRECTORY
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Dwarf directory";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.dwarfdir;
                //DEPLOYMENT DIRECTORY
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Deployment directory";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.deploymentdir;
                //CLUSTER NODES DEPLOYMENT DIRECTORY
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Cluster nodes deployment directory";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.nodelocaltargetdir;
                //SHARED DEPLOYMENT DIRECTORY
                row++;
                sheet.get_Range(name_col + row, name_col + row).Cells.Value2 = "Shared deployment directory";
                sheet.get_Range(value_col + row, value_col + row).Cells.Value2 = gsettings.sdeploymentdir;

                row = gs_dwarf_sum_row;

                #endregion

                int chartwidth = 0;
                int entrycount = 0;

                foreach (Dwarf2 _dwarf in dwarfs)
                {
                    entrycount++;
                    #region WRITE SUMMARY
                    row++;
                    //Dwarf name	Platform	Parallel	Input	Timing	"Input file"	"Result file"	"Profile file"  "Execution string"
                    sheet.get_Range(gs_dwarf_exec_dname_col + row, gs_dwarf_exec_dname_col + row).Cells.Value2 = _dwarf.internalname.ToString();
                    sheet.get_Range(gs_dwarf_exec_dplatform_col + row, gs_dwarf_exec_dplatform_col + row).Cells.Value2 = _dwarf.platform.ToString();
                    sheet.get_Range(gs_dwarf_exec_dparallel_col + row, gs_dwarf_exec_dparallel_col + row).Cells.Value2 = _dwarf.parallel.ToString();
                    sheet.get_Range(gs_dwarf_exec_dsize_col + row, gs_dwarf_exec_dsize_col + row).Cells.Value2 = _dwarf.size.ToString();
                    sheet.get_Range(gs_dwarf_exec_dtiming_col + row, gs_dwarf_exec_dtiming_col + row).Cells.Value2 = _dwarf.time.ToString();
                    sheet.get_Range(gs_dwarf_exec_dinfile_col + row, gs_dwarf_exec_dinfile_col + row).Cells.Value2 = _dwarf.inputfile.ToString();
                    sheet.get_Range(gs_dwarf_exec_drfile_col + row, gs_dwarf_exec_drfile_col + row).Cells.Value2 = _dwarf.resultfile.ToString();
                    sheet.get_Range(gs_dwarf_exec_dpfile_col + row, gs_dwarf_exec_dpfile_col + row).Cells.Value2 = _dwarf.profilefile.ToString();
                    sheet.get_Range(gs_dwarf_exec_execstr_col + row, gs_dwarf_exec_execstr_col + row).Cells.Value2 = _dwarf.log_process_execution_string;

                    int _chartwidth = _dwarf.internalname.ToString().Length;

                    if (_chartwidth < _dwarf.platform.ToString().Length)
                    {
                        _chartwidth = _dwarf.platform.ToString().Length;
                    }
                    if (_chartwidth < _dwarf.parallel.ToString().Length)
                    {
                        _chartwidth = _dwarf.parallel.ToString().Length;
                    }
                    if (_chartwidth < _dwarf.inputfile.ToString().Length)
                    {
                        _chartwidth = _dwarf.inputfile.ToString().Length;
                    }

                    chartwidth += (int)(_chartwidth * 1.4);
                    #endregion
                    #region WRITE COMPARISON RESULTS
                    //Microsoft.Office.Interop.Excel.Worksheet comparesheet = FindSheet(_dwarf.internalname.ToString(), sheets);
                    //comparesheet.Visible = XlSheetVisibility.xlSheetVisible;
                    ////write name:
                    //Range cname = sheet.get_Range(namecell, namecell);
                    //cname.Value2 = _dwarf.internalname.ToString();

                    //string column = "";
                    //int crow = 0;

                    //string size = _dwarf.size;
                    //string parallel = _dwarf.size;
                    //string platform = _dwarf.platform;



                    //if (size.Contains("small"))
                    //    row = 13;
                    //else if (size.Contains("medium"))
                    //    row = 14;
                    //else if (size.Contains("large"))
                    //    row = 15;

                    //if (platform.Contains("managed"))
                    //{
                    //    if (parallel.Contains("serial"))
                    //        column = m_serial;
                    //    else if (parallel.Contains("tpl"))
                    //        column = m_nt;
                    //    else if (parallel.Contains("mpi"))
                    //        column = m_tpl;
                    //    else if (parallel.Contains("hybrid"))
                    //        column = m_mpinet;
                    //}
                    //else
                    //{
                    //    if (parallel.Contains("serial"))
                    //        column = u_serial;
                    //    else if (parallel.Contains("omp"))
                    //        column = u_nt;
                    //    else if (parallel.Contains("mpi"))
                    //        column = u_openmp;
                    //    else if (parallel.Contains("hybrid"))
                    //        column = u_mpi;
                    //}


                    //Microsoft.Office.Interop.Excel.Range crange = comparesheet.get_Range(column + crow.ToString(), column + crow.ToString());
                    //crange.Cells.Value2 = _dwarf.time.ToString();
                    #endregion

                }
                CreateChartReport(workbook, sheet, timeflag, entrycount, chartwidth);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error occured when writing data to Excel: " + e.ToString());
            }

            if (createnewfile)
            {
                workbook.SaveAs(
                        excelfilename,
                        Type.Missing,
                        Type.Missing,
                        Type.Missing,
                        Type.Missing,
                        Type.Missing,
                        XlSaveAsAccessMode.xlNoChange,
                        Type.Missing,
                        Type.Missing,
                        Type.Missing,
                        Type.Missing,
                        Type.Missing);
            }
            else
            {
                workbook.Save();
            }

            workbook.Close(null, null, null);
            xl.Quit();
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        public static void CreateChartReport(
            Microsoft.Office.Interop.Excel.Workbook workbook,
            Microsoft.Office.Interop.Excel.Worksheet summary,
            string tabname,
            int entrycount,
            int chartwidth)
        {
            Microsoft.Office.Interop.Excel._Chart chart;
            chart = (Microsoft.Office.Interop.Excel._Chart)workbook.Charts.Add(
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing);

            Range data = summary.get_Range("A25:E" + (25 + entrycount).ToString(), Type.Missing);

            chart.ChartWizard(data,
                Microsoft.Office.Interop.Excel.XlChartType.xlColumnClustered,
                Type.Missing,
                Microsoft.Office.Interop.Excel.XlRowCol.xlColumns,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing);

            chart.Name = "Chart " + tabname;
            //chart.Type = 6;
            chart.ChartType = XlChartType.xlColumnClustered;
            chart.ChartStyle = 19;
            chart.AutoScaling = true;
            chart.Location(XlChartLocation.xlLocationAsObject, summary.Name);
            summary.Shapes.Item("Chart 1").Top = (float)80;
            summary.Shapes.Item("Chart 1").Left = (float)620;
            summary.Shapes.Item("Chart 1").Width = (float)chartwidth;
        }

        public static void CleanXlsValues(string filename)
        {
            Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();
            xl.Visible = false;
            xl.DisplayAlerts = false;

            //check output file
            //HelperMethods.CheckFile(filename);

            Microsoft.Office.Interop.Excel.Workbook workbook = xl.Workbooks.Open(
                filename,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing);

            try
            {
                Microsoft.Office.Interop.Excel.Sheets sheets = workbook.Worksheets;
                Microsoft.Office.Interop.Excel.Worksheet sheet = FindSheet("Summary", sheets);
                //Delete the summary sheet
                sheet.get_Range(
                    gs_sum_exec_name_col + gs_exec_sum_row,
                    gs_sum_exec_value_col + (gs_exec_sum_row + 17)).Cells.Value2 = "";

                sheet.get_Range(
                    gs_dwarf_exec_dname_col + (gs_dwarf_sum_row + 1),
                    "H" + (gs_dwarf_sum_row + 500)).Cells.Value2 = "";

                //System.Collections.IEnumerator worksheets = sheets.GetEnumerator();
                ////Move to the next
                //worksheets.MoveNext();


                //while (worksheets.MoveNext())
                //{
                //    Microsoft.Office.Interop.Excel.Worksheet wsCurrent = (Worksheet)worksheets.Current;
                //    Range range = wsCurrent.get_Range("C13", "J15");
                //    range.Cells.Value2 = 0;
                //    wsCurrent.Visible = XlSheetVisibility.xlSheetHidden;
                //}
            }
            catch (Exception excelexp)
            {
                DwarfBench.glog.WriteLog("EXCEL_WRITER", "Exception occured while cleaning Excel result file " + filename);
                DwarfBench.glog.WriteLog("EXCEL_WRITER", excelexp.Message);
            }

            workbook.Save();
            workbook.Close(null, null, null);
            workbook = null;

            xl.Quit();
            xl = null;
            GC.Collect();
        }

        public static void PrepareNewExcelFile(Workbook workbook)
        {
            while ((workbook.Worksheets).GetEnumerator().MoveNext())
            {
                try
                {
                    Worksheet ws = (Worksheet)workbook.Worksheets.GetEnumerator().Current;
                    if (ws.Name.Contains("sheet"))
                        ws.Delete();
                }
                catch (Exception) { } //the last one will throw an exception
            }
        }



    }
}
